#include "DijkstraTest.h"

namespace zbp
{
	using namespace boost;

double dijkstra_CompleteGraph_test(int source_vertex, CompleteGraph<int> graph, bool display)
{
	vector<int> d, p;

	clock_t ticks = clock();

	graph.dijkstra(source_vertex, d, p);

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "CompleteGraph class: dijkstra method for node " << source_vertex << endl << endl;
		display_vector(d, std::numeric_limits<int>::max());
		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double dijkstra_SimpleGraph_test(int source_vertex, SimpleGraph graph, bool display)
{
	vector<int> d, p;

	clock_t ticks = clock();

	bool result = graph.dijkstra(source_vertex, d, p);

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "SimpleGraph class: dijkstra method for node " << source_vertex << endl << endl;

		if (result)
			display_vector(d, std::numeric_limits<int>::max());
		else
			cout << "Negative weight found." << endl;

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double dijkstra_boost_test(int source_vertex, BoostEdge* edge_array, int* weights, int nodes_count, int edges_count, bool display)
{
	typedef adjacency_list < listS, vecS, directedS,
	no_property, property < edge_weight_t, int > > graph_t;
	typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
	typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;	
					
	#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
		graph_t g(nodes_count);
		property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
		for (std::size_t j = 0; j < edges_count; ++j) {
			edge_descriptor e; bool inserted;
			boost::tie(e, inserted) = add_edge(edge_array[j].first, edge_array[j].second, g);
			weightmap[e] = weights[j];
		}
	#else
		graph_t g(edge_array, edge_array + edges_count, weights, nodes_count);
		property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
	#endif
	std::vector<vertex_descriptor> p(num_vertices(g));
	std::vector<int> d(num_vertices(g));
	vertex_descriptor s = vertex(source_vertex, g);

	clock_t ticks = clock();

	#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
		// VC++ has trouble with the named parameters mechanism
		property_map<graph_t, vertex_index_t>::type indexmap = get(vertex_index, g);
		dijkstra_shortest_paths(g, s, &p[0], &d[0], weightmap, indexmap, 
							std::less<int>(), closed_plus<int>(), 
							(std::numeric_limits<int>::max)(), 0,
							default_dijkstra_visitor());
	#else
		//dijkstra_shortest_paths(g, s, );
		//dijkstra_shortest_paths(g, s);
		dijkstra_shortest_paths_no_color_map(g, s, predecessor_map(&p[0]).distance_map(&d[0]));

	#endif

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "Boost: dijkstra_shortest_paths_no_color_map function for node " << source_vertex << endl << endl;
		display_vector(d, std::numeric_limits<int>::max());
		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double n_dijkstra_CompleteGraph_test(CompleteGraph<int> graph, bool display)
{
	int n = graph.get_nodes_count();
	DistanceMatrix<int> d(n, 0);
	DistanceMatrix<int> p(n, 0);

	clock_t ticks = clock();

	for (int i = 0; i < n; i++)
	{
		graph.dijkstra(i, d[i], p[i]);
	}

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "CompleteGraph class: dijkstra method for all nodes" << endl << endl;
		d.display();
		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double n_dijkstra_SimpleGraph_test(SimpleGraph graph, bool display)
{
	int n = graph.get_nodes_count();
	DistanceMatrix<int> d(n, 0);
	DistanceMatrix<int> p(n, 0);

	clock_t ticks = clock();

	bool result = true;
	for (int i = 0; i < n && result; i++)
	{
		result = graph.dijkstra(i, d[i], p[i]);
	}

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "SimpleGraph class: dijkstra method for all nodes" << endl << endl;

		if (result)
			d.display();
		else
			cout << "Negative weight found." << endl;

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double n_dijkstra_boost_test(BoostEdge* edge_array, int* weights, int nodes_count, int edges_count, bool display)
{
	typedef adjacency_list < listS, vecS, directedS,
	no_property, property < edge_weight_t, int > > graph_t;
	typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
	typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;	
					
	#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
		graph_t g(nodes_count);
		property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
		for (std::size_t j = 0; j < edges_count; ++j) {
			edge_descriptor e; bool inserted;
			boost::tie(e, inserted) = add_edge(edge_array[j].first, edge_array[j].second, g);
			weightmap[e] = weights[j];
		}
	#else
		graph_t g(edge_array, edge_array + edges_count, weights, nodes_count);
		property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
	#endif
	std::vector<vertex_descriptor> p(num_vertices(g));
	std::vector<int> d(num_vertices(g));

	//DistanceMatrix<int>* d = new DistanceMatrix<int>[nodes_count];
	DistanceMatrix<int> d1(nodes_count, nodes_count);

	clock_t ticks = clock();

	for (int i = 0; i < nodes_count; i++)
	{
		vertex_descriptor s = vertex(i, g);		

		#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
			// VC++ has trouble with the named parameters mechanism
			property_map<graph_t, vertex_index_t>::type indexmap = get(vertex_index, g);
			dijkstra_shortest_paths(g, s, &p[0], &d[0], weightmap, indexmap, 
								std::less<int>(), closed_plus<int>(), 
								(std::numeric_limits<int>::max)(), 0,
								default_dijkstra_visitor());
		#else
			//dijkstra_shortest_paths(g, s, );
			//dijkstra_shortest_paths(g, s);
			dijkstra_shortest_paths_no_color_map(g, s, predecessor_map(&p[0]).distance_map(&d1[i][0]));
		#endif

		//p.clear();
	}

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "Boost: dijkstra_shortest_paths_no_color_map function for all nodes" << endl << endl;
		d1.display();
		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

void dijkstra_tests_run(SimpleGraph simple_graph, 
						CompleteGraph<int> complete_graph,
					    BoostEdge* boost_edges, 
					    int* boost_weights,
					    int nodes_count, int edges_count,
						int source_vertex)
{
	dijkstra_CompleteGraph_test(source_vertex, complete_graph, true);
	dijkstra_SimpleGraph_test(source_vertex, simple_graph, true);
	dijkstra_boost_test(source_vertex, boost_edges, boost_weights, nodes_count, edges_count, true);

	n_dijkstra_CompleteGraph_test(complete_graph, true);
	n_dijkstra_SimpleGraph_test(simple_graph, true);
	n_dijkstra_boost_test(boost_edges, boost_weights, nodes_count, edges_count, true);
}

}